package org.example.physics_engine.body;

import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
import org.example.physics_engine.Epsilon;
import org.example.physics_engine.geometry.Interval;
import org.example.physics_engine.geometry.Vector2d;

//物体的旋转/位移
@Getter
@Setter
@ToString
@NoArgsConstructor
public class Transform {

    //旋转角度的cos值，默认不旋转
    protected double cost = 1.0;
    //旋转角度的sin值
    protected double sint = 0.0;
    //相对于原点在x轴上的偏移，相当于在该世界中的x坐标
    protected double x = 0.0;
    //相对于原点在y轴上的偏移，相当于在该世界中的y坐标
    protected double y = 0.0;

    public Transform(double cost, double sint, double x, double y) {
        this.cost = cost;
        this.sint = sint;
        this.x = x;
        this.y = y;
    }

    public Transform(Transform transform) {
        this.cost = transform.cost;
        this.sint = transform.sint;
        this.x = transform.x;
        this.y = transform.y;
    }

     //绕着某一点做旋转
     //参数是旋转角度的cos、sin值和x、y坐标
    public void rotate(double c, double s, double x, double y) {
        double cosT = this.cost;
        double sinT = this.sint;
        this.cost = Interval.clamp(c * cosT - s * sinT, -1.0, 1.0);
        this.sint = Interval.clamp(s * cosT + c * sinT, -1.0, 1.0);
        if (Math.abs(this.cost) < Epsilon.E) {
            this.cost = 0;
        }
        if (Math.abs(this.sint) < Epsilon.E) {
            this.sint = 0;
        }
        double cx = this.x - x;
        double cy = this.y - y;
        this.x = c * cx - s * cy + x;
        this.y = s * cx + c * cy + y;
    }

    //绕着某一点旋转
    //参数是旋转角度和旋转点坐标
    public void rotate(double theta, double x, double y) {
        this.rotate(Math.cos(theta), Math.sin(theta), x, y);
    }

    //沿参数Vector2d的x和y平移
    public void translate(double x, double y) {
        this.x += x;
        this.y += y;
    }

    //沿参数Vector2d平移
    public void translate(Vector2d vector) {
        this.translate(vector.x, vector.y);
    }

    //将本变换赋予给定Vector的 x 坐标并返回结果
    public double getTransformedX(Vector2d vector) {
        return this.cost * vector.x - this.sint * vector.y + this.x;
    }

    //将本变换赋予给定Vector的 y 坐标并返回结果
    public double getTransformedY(Vector2d vector) {
        return this.sint * vector.x + this.cost * vector.y + this.y;
    }

    //将本变换赋予给定Vector，返回变换后的新变量
    public Vector2d getTransformed(Vector2d vector) {
        Vector2d tv = new Vector2d();
        double x = vector.x;
        double y = vector.y;
        tv.x = this.cost * x - this.sint * y + this.x;
        tv.y = this.sint * x + this.cost * y + this.y;
        return tv;
    }

    //对给定Vector进行逆旋转平移变换，返回变换后的新向量
    public Vector2d getInverseTransformed(Vector2d vector) {
        Vector2d tv = new Vector2d();
        double tx = vector.x - this.x;
        double ty = vector.y - this.y;
        tv.x = this.cost * tx + this.sint * ty;
        tv.y = -this.sint * tx + this.cost * ty;
        return tv;
    }

    //对给定Vector只进行旋转变换，返回变换后的新向量
    public Vector2d getTransformedRotate(Vector2d vector) {
        Vector2d v = new Vector2d();
        double x = vector.x;
        double y = vector.y;
        v.x = this.cost * x - this.sint * y;
        v.y = this.sint * x + this.cost * y;
        return v;
    }

    //对给定Vector只进行旋转变换，无返回值
    public void transformRotate(Vector2d vector) {
        double x = vector.x;
        double y = vector.y;
        vector.x = this.cost * x - this.sint * y;
        vector.y = this.sint * x + this.cost * y;
    }

    //对给定Vector只进行逆旋转变换，返回变换后的新向量
    public Vector2d getInverseTransformedRotate(Vector2d vector) {
        Vector2d v = new Vector2d();
        double x = vector.x;
        double y = vector.y;
        // sin(-a) = -sin(a)
        v.x = this.cost * x + this.sint * y;
        v.y = -this.sint * x + this.cost * y;
        return v;
    }

    //获取旋转角度，返回角度制，返回范围在-180~180之间
    //java.lang.Math.asin(double a) 返回角度的反正弦值，范围为 -pi/2 到 pi/2
    //java.lang.Math.acos(double a) 返回角度的反余弦值，范围为 0.0 到 pi
    //Java中Math.toDegrees ()将-π/2到π/2之间的弧度值转化为度。
    public double getRotationAngle() {
        // Copied from Rotation class; See there for more info
        double acos = Math.acos(this.cost);
        double angle = (this.sint >= 0)? acos: -acos;
        return Math.toDegrees(angle);
    }

    //复制一个和本平移旋转相同的新实例返回
    public Transform copy() {
        return new Transform(this.cost, this.sint, this.x, this.y);
    }

}
